/*
 * libroxsd - a portable, lightweight XSD validation library
 * Copyright (C) 2012  Emmanuel Deloget
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

#include <errno.h>
#include "roxsd.h"
#include "roxsd-list.h"
#include "roxsd-compiler.h"

/*
 * Private functions
 */

static inline unsigned int roxsdi_schema_count(xsdenv_t *xsdenv)
{
	return list_count(xsdenv->compilers);
}

static inline unsigned int roxsdi_validation_error_count(xsdenv_t *xsdenv)
{
	return list_count(xsdenv->errors);
}

static inline void roxsdi_clear(xsdenv_t *xsdenv)
{
	xsderr_t *err;

	while (xsdenv->errors) {
		err = xsdenv->errors;
		xsdenv->errors = list_unlink(xsdenv->errors, err);
		/*
		 * errstr is const, but we need to free it as it was allocated
		 * with a call to strdup()
		 */
		free((char*)err->errstr);
		free(err);
	}

	/* TODO - do the work */

	xsdenv;
}

/*
 * Public API
 */

xsdenv_t *roxsd_create_env(void)
{
	xsdenv_t *env;

	env = malloc(sizeof(xsdenv_t));
	if (env) {
		memset(env, 0, sizeof(xsdenv_t));
		return env;
	}
	return NULL;
}

int roxsd_compile_schema(xsdenv_t *xsdenv, node_t *sroot)
{
	if (!sroot || !xsdenv) {
		errno = EINVAL;
		return -1;
	}

	/*
	 * this version limits the number of schema to one. This is
	 * a harsh limitation, and it will go away in subsequent
	 * releases
	 */
	if (roxsdi_schema_count(xsdenv)) {
		errno = EBUSY;
		return -1;
	}

	return roxsdi_compile_schema(xsdenv, sroot);
}

int roxsd_validate_document(xsdenv_t *xsdenv, node_t *root)
{
	if (!xsdenv || !root) {
		errno = EINVAL;
		return -1;
	}

	/* TODO - do the work */

	return 0;
}

unsigned int roxsd_validation_error_count(xsdenv_t *xsdenv)
{
	if (!xsdenv) {
		return 0;
	}
	return roxsdi_validation_error_count(xsdenv);
}

xsderr_t * roxsd_validation_error(xsdenv_t *xsdenv, unsigned int erridx)
{
	if (!xsdenv) {
		errno = EINVAL;
		return NULL;
	}

	if (erridx > roxsdi_validation_error_count(xsdenv)) {
		errno = EINVAL;
		return NULL;
	}

	/* TODO - do the work */

	return NULL;
}

void roxsd_clear(xsdenv_t *xsdenv)
{
	if (xsdenv) {
		roxsdi_clear(xsdenv);
	}
}

void roxsd_release(xsdenv_t *xsdenv)
{
	if (xsdenv) {
		roxsdi_clear(xsdenv);
		free(xsdenv);
	}
}

unsigned int roxsd_schema_count(xsdenv_t *xsdenv)
{
	if (xsdenv) {
		return roxsdi_schema_count(xsdenv);
	}
	return 0;
}

xsderr_t * roxsd_get_first_error(xsdenv_t *xsdenv)
{
	return xsdenv->errors;
}

xsderr_t * roxsd_get_next_error(xsderr_t *err)
{
	if (err) {
		return (xsderr_t*)(list_next(err));
	}
	return NULL;
}

int roxsd_get_error_desc(xsderr_t *err, int *errcode, const char ** errstr, node_t **errnode)
{
	if (err && errcode) {
		*errcode = err->errcode;
		if (errstr) *errstr = err->errstr;
		if (errnode) *errnode = err->errnode;
		return 0;
	}
	errno = EINVAL;
	return -1;
}

